/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.openide.src.nodes;
import java.awt.Component;
import java.beans.*;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.lang.reflect.InvocationTargetException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.Arrays;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.DataFlavor;
import org.openide.TopManager;
import org.openide.src.*;
import org.openide.nodes.*;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.datatransfer.*;
/** Node representing a Java class.
* @see ClassElement
*
* @author Petr Hamernik
*/
public class ClassElementNode extends MemberElementNode {
/** Return value of getIconAffectingProperties method. */
private static final String[] ICON_AFFECTING_PROPERTIES = new String[] {
PROP_CLASS_OR_INTERFACE
};
/** Menu labels */
private static final String MENU_CREATE_BLOCK;
private static final String MENU_CREATE_VARIABLE;
private static final String MENU_CREATE_CONSTRUCTOR;
private static final String MENU_CREATE_METHOD;
private static final String MENU_CREATE_CLASS;
private static final String MENU_CREATE_INTERFACE;
static {
ResourceBundle bundle = NbBundle.getBundle(ClassElementNode.class);
MENU_CREATE_BLOCK = bundle.getString("MENU_CREATE_BLOCK");
MENU_CREATE_VARIABLE = bundle.getString("MENU_CREATE_VARIABLE");
MENU_CREATE_CONSTRUCTOR = bundle.getString("MENU_CREATE_CONSTRUCTOR");
MENU_CREATE_METHOD = bundle.getString("MENU_CREATE_METHOD");
MENU_CREATE_CLASS = bundle.getString("MENU_CREATE_CLASS");
MENU_CREATE_INTERFACE = bundle.getString("MENU_CREATE_INTERFACE");
}
/** Create a new class node.
* @param element class element to represent
* @param children node children
* @param writeable <code>true</code> to be writable
*/
public ClassElementNode(ClassElement element, Children children, boolean writeable) {
super(element, children, writeable);
setElementFormat (((ClassElement)element).isInterface() ?
sourceOptions.getInterfaceElementFormat() :
sourceOptions.getClassElementFormat());
}
/* Resolve the current icon base.
* @return icon base string.
*/
protected String resolveIconBase() {
return ((ClassElement)element).isInterface() ? INTERFACE : CLASS;
}
/* This method is used for resolving the names of the properties,
* which could affect the icon (such as "modifiers").
* @return the appropriate array.
*/
protected String[] getIconAffectingProperties() {
return ICON_AFFECTING_PROPERTIES;
}
/* This method resolve the appropriate hint format for the type
* of the element. It defines the short description.
*/
protected ElementFormat getHintElementFormat() {
return ((ClassElement)element).isInterface() ?
sourceOptions.getInterfaceElementLongFormat() :
sourceOptions.getClassElementLongFormat();
}
/* Creates property set for this node */
protected Sheet createSheet () {
Sheet sheet = Sheet.createDefault();
Sheet.Set ps = sheet.get(Sheet.PROPERTIES);
ps.put(createModifiersProperty(writeable));
ps.put(createNameProperty(writeable));
if (((ClassElement)element).isClass())
ps.put(createSuperclassProperty(writeable));
ps.put(createInterfacesProperty(writeable));
return sheet;
}
/** Remove this class from its declaring class or source file.
*
* @exception IOException if the containing element refuses to delete it
*/
public void destroy() throws IOException {
SourceEditSupport.invokeAtomicAsUser(element, new SourceEditSupport.ExceptionalRunnable() {
public void run() throws SourceException {
ClassElement el = (ClassElement) element;
if (el.getDeclaringClass() != null) {
el.getDeclaringClass().removeClass(el);
}
else {
el.getSource().removeClass(el);
}
}
});
super.destroy();
}
public Component getCustomizer() {
return new ClassCustomizer((ClassElement)element);
}
public boolean hasCustomizer() {
return true;
}
/* Accumulate the paste types that this node can handle
* for a given transferable.
* <P>
* The default implementation simply tests whether the transferable supports
* {@link NodeTransfer#nodePasteFlavor}, and if so, it obtains the paste types
* from the {@link NodeTransfer.Paste transfer data} and inserts them into the set.
*
* @param t a transferable containing clipboard data
* @param s a set of {@link PasteType}s that will have added to it all types
* valid for this node
*/
protected void createPasteTypes (final Transferable t, java.util.List s) {
if (writeable) {
for (int i = 0; i <= 1; i++) {
final boolean delete = (i == 1);
final Element addingElement = (Element) NodeTransfer.cookie(t,
delete ? NodeTransfer.MOVE : NodeTransfer.COPY, Element.class);
if (addingElement != null) {
s.add(new PasteType() {
public Transferable paste() throws IOException {
pasteElement(addingElement, delete);
return delete ? ExTransferable.EMPTY : null;
}
});
}
}
}
super.createPasteTypes(t, s);
}
/** Paste element into this class.
* @param addingElement Element to add.
* @param delete Whether element should be deleted from the original class
* @exception IOException if any proble occured
*/
void pasteElement(final Element addingElement, final boolean delete) throws IOException {
SourceEditSupport.invokeAtomicAsUser(element, new SourceEditSupport.ExceptionalRunnable() {
public void run() throws SourceException {
ClassElement clazz = (ClassElement) element;
if (addingElement instanceof InitializerElement) {
InitializerElement e = (InitializerElement)addingElement;
clazz.addInitializer(e);
}
if (addingElement instanceof FieldElement) {
clazz.addField((FieldElement)addingElement);
}
else if (addingElement instanceof MethodElement) {
clazz.addMethod((MethodElement)addingElement);
}
else if (addingElement instanceof ConstructorElement) {
clazz.addConstructor((ConstructorElement)addingElement);
}
else if (addingElement instanceof ClassElement) {
clazz.addClass((ClassElement)addingElement);
}
}
});
if (delete) {
final ClassElement origClazz;
final SourceElement src;
if (addingElement instanceof InitializerElement) {
origClazz = ((InitializerElement)addingElement).getDeclaringClass();
} else if (addingElement instanceof ClassElement) {
origClazz = (ClassElement)addingElement;
} else if (addingElement instanceof MemberElement) {
origClazz = ((MemberElement)addingElement).getDeclaringClass();
} else {
origClazz = null;
}
if (origClazz != null) {
src = origClazz.getSource();
} else {
src = null;
}
SourceEditSupport.ExceptionalRunnable r = new SourceEditSupport.ExceptionalRunnable() {
public void run() throws SourceException {
if (addingElement instanceof InitializerElement) {
InitializerElement e = (InitializerElement)addingElement;
if (origClazz != null)
origClazz.removeInitializer(e);
} else if (addingElement instanceof MemberElement) {
if (origClazz != null) {
if (addingElement instanceof FieldElement) {
origClazz.removeField((FieldElement)addingElement);
} else if (addingElement instanceof MethodElement) {
origClazz.removeMethod((MethodElement)addingElement);
} else if (addingElement instanceof ConstructorElement) {
origClazz.removeConstructor((ConstructorElement)addingElement);
} else if (addingElement instanceof ClassElement) {
ClassElement parent = origClazz.getDeclaringClass();
if (parent == null) {
if (src != null) {
src.removeClass((ClassElement)addingElement);
}
} else {
parent.removeClass((ClassElement)addingElement);
}
}
}
}
}
};
if (src == null) {
try {
r.run();
} catch (SourceException e) {
throw new IOException(e.getMessage());
}
} else {
SourceEditSupport.invokeAtomicAsUser(addingElement, r);
}
}
}
/** Create a node property for the superclass of this class.
* @param canW if <code>false</code>, property will be read-only
* @return the property
*/
protected Node.Property createSuperclassProperty(boolean canW) {
return new ElementProp(PROP_SUPERCLASS, String.class, canW) {
/** Gets the value */
public Object getValue () {
Identifier id = ((ClassElement)element).getSuperclass();
return id == null ? "" : id.getFullName(); // NOI18N
}
/** Sets the value */
public void setValue(final Object val) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
super.setValue(val);
if (!(val instanceof String))
throw new IllegalArgumentException();
runAtomic(element, new SourceEditSupport.ExceptionalRunnable() {
public void run() throws SourceException {
String str = ((String) val).trim();
Identifier superclass = str.equals("") ? null: Identifier.create(str); // NOI18N
((ClassElement)element).setSuperclass(superclass);
}
});
}
};
}
/** Create a node property for the implemented interfaces of this class.
* (Or, extended interfaces if this is itself an interface.)
* @param canW if <code>false</code>, property will be read-only
* @return the property
*/
protected Node.Property createInterfacesProperty(boolean canW) {
ElementProp prop = new ElementProp(PROP_INTERFACES, Identifier[].class, canW) {
/** Gets the value */
public Object getValue () {
return ((ClassElement)element).getInterfaces();
}
/** Sets the value */
public void setValue(final Object val) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
super.setValue(val);
if (!(val instanceof Identifier[]))
throw new IllegalArgumentException();
runAtomic(element, new SourceEditSupport.ExceptionalRunnable() {
public void run() throws SourceException {
((ClassElement)element).setInterfaces((Identifier[])val);
}
});
}
};
if (((ClassElement)element).isInterface()) {
prop.setDisplayName(bundle.getString("PROP_superInterfaces"));
prop.setShortDescription(bundle.getString("HINT_superInterfaces"));
}
return prop;
}
/* Get the new types that can be created in this node.
* For example, a node representing a Java package will permit classes to be added.
* @return array of new type operations that are allowed
*/
public NewType[] getNewTypes() {
if (writeable) {
return SourceEditSupport.createNewTypes((ClassElement)element);
}
else {
// no new types
return super.getNewTypes();
}
}
}
/*
* Log
* 22 src-jtulach1.21 1/12/00 Petr Hamernik i18n using perl script
* (//NOI18N comments added)
* 21 src-jtulach1.20 1/9/00 Petr Hamernik user fault tolerance -
* trim() is used in the string properties (name, superclass)
* 20 src-jtulach1.19 11/29/99 Petr Hamernik customizers
* 19 src-jtulach1.18 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 18 src-jtulach1.17 9/13/99 Petr Hamernik runAsUser implemented and
* used
* 17 src-jtulach1.16 7/6/99 Jesse Glick Removing unused imports.
* 16 src-jtulach1.15 7/1/99 Petr Hamernik Clipboard operations on
* source Elements
* 15 src-jtulach1.14 6/28/99 Petr Hamernik new hierarchy under
* ClassChildren
* 14 src-jtulach1.13 6/24/99 Jesse Glick Gosh-honest HelpID's.
* 13 src-jtulach1.12 6/8/99 Ian Formanek ---- Package Change To
* org.openide ----
* 12 src-jtulach1.11 5/14/99 Petr Hamernik NewTypes improved (Class
* x Interface new types)
* 11 src-jtulach1.10 5/12/99 Petr Hamernik Identifier implementation
* updated
* 10 src-jtulach1.9 5/10/99 Petr Hamernik New types improved
* 9 src-jtulach1.8 4/30/99 Petr Hamernik property editors moved
* away
* 8 src-jtulach1.7 4/27/99 Jesse Glick new HelpCtx () ->
* HelpCtx.DEFAULT_HELP.
* 7 src-jtulach1.6 4/21/99 Petr Hamernik superclass property bug
* fixed
* 6 src-jtulach1.5 4/20/99 Petr Hamernik superclass property
* changed
* 5 src-jtulach1.4 4/2/99 Jesse Glick [JavaDoc]
* 4 src-jtulach1.3 4/1/99 Jan Jancura Object browser support
* 3 src-jtulach1.2 3/19/99 Jaroslav Tulach
* 2 src-jtulach1.1 3/18/99 Petr Hamernik
* 1 src-jtulach1.0 3/18/99 Petr Hamernik
* $
*/